/**
 * @file dbus_client.c
 * @brief D-Bus客户端测试程序 - 发送信号和调用方法
 */
#include "dbus_common.h"
#include <pthread.h>
#define MAX_MESSAGE_SIZE (16 * 1024 * 1024) /* 16MB 限制 */
#define MAX_PARAM_SIZE (1024 * 1024)        /* 1MB 参数限制 */

static pthread_mutex_t g_dbus_mutex = PTHREAD_MUTEX_INITIALIZER;

static DBusConnection *g_connection = NULL;

/**
 * @brief 初始化客户端
 */
static int initialize_client()
{
    DBusError error;
    int result = FALSE;

    pthread_mutex_lock(&g_dbus_mutex);

    if (g_connection != NULL)
    {
        pthread_mutex_unlock(&g_dbus_mutex);
        return TRUE; /* 已经初始化 */
    }

    dbus_error_init(&error);

    /* 连接到会话总线 */
    g_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
    CHECK_ERROR(error);

    if (!g_connection)
    {
        fprintf(stderr, "连接D-Bus失败\n");
        result = FALSE;
    }
    else
    {
        printf("客户端初始化成功\n");
        result = TRUE;
    }

    pthread_mutex_unlock(&g_dbus_mutex);
    return result;
}

/**
 * @brief 发送信号
 */
static int send_signal(const char *signal_data)
{
    pthread_mutex_lock(&g_dbus_mutex);
    DBusMessage *message = NULL;
    DBusMessageIter args;
    int result = FALSE;
    size_t data_len;

    if (!signal_data)
    {
        fprintf(stderr, "信号数据为空\n");
        goto cleanup;
    }

    data_len = strlen(signal_data);
    if (data_len > MAX_PARAM_SIZE)
    {
        fprintf(stderr, "信号数据过大: %zu 字节 (最大: %d 字节)\n",
                data_len, MAX_PARAM_SIZE);
        goto cleanup;
    }

    if (!check_connection_status())
    {
        fprintf(stderr, "D-Bus连接状态异常\n");
        goto cleanup;
    }

    /* 检查目标服务是否可用 ，优化一下，不可用放到队列，等待可用再发送*/
    if (!is_service_available())
    {
        fprintf(stderr, "目标服务 %s 未启动或不可用，信号可能无法被接收\n", TEST_SERVICE_NAME);
        /* 注意：信号是广播性质，即使服务不存在也可以发送，只是可能没有接收者 */
        printf("警告：继续发送信号，但可能没有接收者\n");
    }

    /* 创建信号消息 */
    message = dbus_message_new_signal(TEST_OBJECT_PATH, TEST_INTERFACE_NAME,
                                      TEST_SIGNAL_NAME);
    if (!message)
    {
        fprintf(stderr, "创建信号消息失败\n");
        goto cleanup;
    }

    /* 添加信号参数 */
    dbus_message_iter_init_append(message, &args);
    if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &signal_data))
    {
        fprintf(stderr, "添加信号参数失败\n");
        goto cleanup;
    }

    /* 发送信号 */
    if (!dbus_connection_send(g_connection, message, NULL))
    {
        fprintf(stderr, "发送信号失败\n");
        goto cleanup;
    }

    dbus_connection_flush(g_connection);
    result = TRUE;
    printf("信号发送成功: %s (大小: %zu 字节)\n", signal_data, data_len);

cleanup:
    if (message)
    {
        dbus_message_unref(message);
    }
    pthread_mutex_unlock(&g_dbus_mutex);
    return result;
}

/**
 * @brief 调用方法
 */
static int call_method(const char *method_param)
{
    pthread_mutex_lock(&g_dbus_mutex);
    DBusMessage *message = NULL;
    DBusMessage *reply = NULL;
    DBusMessageIter args;
    DBusError error;
    char *response = NULL;
    DBusPendingCall *pending = NULL;
    int result = FALSE;
    size_t param_len;

    if (!method_param)
    {
        fprintf(stderr, "方法参数为空\n");
        goto cleanup;
    }

    param_len = strlen(method_param);
    if (param_len > MAX_PARAM_SIZE)
    {
        fprintf(stderr, "方法参数过大: %zu 字节 (最大: %d 字节)\n",
                param_len, MAX_PARAM_SIZE);
        goto cleanup;
    }

    if (!check_connection_status())
    {
        fprintf(stderr, "D-Bus连接状态异常\n");
        goto cleanup;
    }

    /* 检查目标服务是否可用，如果不可用则等待3秒 */
    if (!is_service_available())
    {
        printf("目标服务 %s 未启动，等待服务启动...\n", TEST_SERVICE_NAME);
        /* 释放锁，允许其他线程执行 */
        pthread_mutex_unlock(&g_dbus_mutex);
        /* 在不持有锁的情况下等待服务 */
        int service_ready = wait_for_service_available(3);
        /* 重新获取锁 */
        pthread_mutex_lock(&g_dbus_mutex);
        if (!service_ready)
        {
            fprintf(stderr, "等待服务超时，无法调用方法\n");
            printf("提示：请先启动服务端程序\n");
            goto cleanup;
        }
    }

    /* 重新检查连接状态（可能在等待期间连接已断开） */
    if (!check_connection_status())
    {
        fprintf(stderr, "D-Bus连接状态异常\n");
        goto cleanup;
    }

    dbus_error_init(&error);

    /* 创建方法调用消息 */
    message = dbus_message_new_method_call(TEST_SERVICE_NAME, TEST_OBJECT_PATH,
                                           TEST_INTERFACE_NAME, TEST_METHOD_NAME);
    if (!message)
    {
        fprintf(stderr, "创建方法调用消息失败\n");
        goto cleanup;
    }

    /* 添加方法参数 */
    dbus_message_iter_init_append(message, &args);
    if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &method_param))
    {
        fprintf(stderr, "添加方法参数失败\n");
        goto cleanup;
    }

    /* 异步发送方法调用，设置2000ms超时 */
    if (!dbus_connection_send_with_reply(g_connection, message, &pending, 2000))
    {
        fprintf(stderr, "发送方法调用失败（可能是内存不足或连接问题）\n");
        goto cleanup;
    }

    if (!pending)
    {
        fprintf(stderr, "创建pending调用失败，服务可能不可用\n");
        goto cleanup;
    }

    /* 方法调用消息被立即发送(将所有挂起的消息立即发送到 D-Bus 总线) */
    dbus_connection_flush(g_connection);

    /* 释放锁，避免阻塞其他线程 */
    pthread_mutex_unlock(&g_dbus_mutex);

    /* 等待响应完成或超时 */
    dbus_pending_call_block(pending);

    /* 重新获取锁来处理响应 */
    pthread_mutex_lock(&g_dbus_mutex);

    /* 检查调用是否完成 */
    if (!dbus_pending_call_get_completed(pending))
    {
        fprintf(stderr, "方法调用未完成（可能网络问题）\n");
        goto cleanup;
    }

    /* 获取回复 */
    reply = dbus_pending_call_steal_reply(pending);
    if (!reply)
    {
        fprintf(stderr, "方法调用没有回复\n");
        goto cleanup;
    }

    /* 详细的错误处理 */
    if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
    {
        const char *error_name = dbus_message_get_error_name(reply);
        const char *error_msg = NULL;

        /* 尝试获取错误详细信息 */
        if (dbus_message_iter_init(reply, &args) &&
            dbus_message_iter_get_arg_type(&args) == DBUS_TYPE_STRING)
        {
            dbus_message_iter_get_basic(&args, &error_msg);
        }

        if (error_name && strcmp(error_name, DBUS_ERROR_TIMEOUT) == 0)
        {
            fprintf(stderr, "方法调用超时（2000ms）\n");
        }
        else if (error_name && strcmp(error_name, DBUS_ERROR_NO_REPLY) == 0)
        {
            fprintf(stderr, "方法调用超时，服务未响应\n");
        }
        else if (error_name && strcmp(error_name, DBUS_ERROR_SERVICE_UNKNOWN) == 0)
        {
            fprintf(stderr, "服务不存在: %s\n", TEST_SERVICE_NAME);
        }
        else
        {
            fprintf(stderr, "方法调用失败: %s%s%s\n",
                    error_name ? error_name : "未知错误",
                    error_msg ? " - " : "",
                    error_msg ? error_msg : "");
        }
        goto cleanup;
    }

    /* 读取正常回复 */
    if (!dbus_message_iter_init(reply, &args))
    {
        printf("方法回复没有参数\n");
    }
    else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args))
    {
        printf("方法回复参数类型不正确\n");
    }
    else
    {
        dbus_message_iter_get_basic(&args, &response);
        printf("方法调用成功，回复: %s\n", response);
    }

    result = TRUE;

cleanup:
    if (message)
    {
        dbus_message_unref(message);
    }
    if (reply)
    {
        dbus_message_unref(reply);
    }
    if (pending)
    {
        dbus_pending_call_unref(pending);
    }
    if (dbus_error_is_set(&error))
    {
        dbus_error_free(&error);
    }
    pthread_mutex_unlock(&g_dbus_mutex);
    return result;
}

/**
 * @brief 显示使用帮助
 */
static void show_usage()
{
    printf("使用方法:\n");
    printf("  signal <消息内容>  - 发送信号\n");
    printf("  method <参数>      - 调用方法\n");
    printf("  quit              - 退出程序\n");
}

int main()
{
    char input[256];
    char command[64];
    char param[192];

    printf("=== D-Bus客户端测试程序 ===\n");

    if (!initialize_client())
    {
        fprintf(stderr, "客户端初始化失败\n");
        return 1;
    }

    show_usage();

    while (TRUE)
    {
        printf("\n请输入命令: ");
        fflush(stdout);

        if (!fgets(input, sizeof(input), stdin))
        {
            break;
        }

        /* 初始化参数数组 */
        memset(command, 0, sizeof(command));
        memset(param, 0, sizeof(param));

        int parsed = sscanf(input, "%63s %191s", command, param);
        if (parsed < 1)
        {
            continue;
        }

        if (strcmp(command, "signal") == 0)
        {
            if (parsed >= 2 && strlen(param) > 0) /* 检查是否解析到参数 */
            {
                send_signal(param);
            }
            else
            {
                printf("请提供信号内容\n");
            }
        }
        else if (strcmp(command, "method") == 0)
        {
            if (parsed >= 2 && strlen(param) > 0) /* 检查是否解析到参数 */
            {
                call_method(param);
            }
            else
            {
                printf("请提供方法参数\n");
            }
        }
        else if (strcmp(command, "quit") == 0)
        {
            break;
        }
        else
        {
            show_usage();
        }
    }

    pthread_mutex_lock(&g_dbus_mutex);
    if (g_connection)
    {
        dbus_connection_unref(g_connection);
        g_connection = NULL;
    }
    pthread_mutex_unlock(&g_dbus_mutex);

    printf("客户端退出\n");
    return 0;
}

/**
 * @brief 检查目标服务是否可用
 */
static int is_service_available()
{
    DBusError error;
    dbus_bool_t exists;

    if (!g_connection)
    {
        return FALSE;
    }

    dbus_error_init(&error);

    /* 检查服务名是否存在 */
    exists = dbus_bus_name_has_owner(g_connection, TEST_SERVICE_NAME, &error);

    if (dbus_error_is_set(&error))
    {
        fprintf(stderr, "检查服务状态失败: %s\n", error.message);
        dbus_error_free(&error);
        return FALSE;
    }

    return exists ? TRUE : FALSE;
}

/**
 * @brief 等待目标服务可用，在等待过程中不持有全局锁
 * @param timeout_seconds 超时时间（秒）
 * @return TRUE if 服务可用, FALSE if 超时
 */
static int wait_for_service_available(int timeout_seconds)
{
    time_t start_time = time(NULL);
    time_t current_time;
    int service_available = FALSE;

    printf("等待服务 %s 启动", TEST_SERVICE_NAME);
    fflush(stdout);

    while (TRUE)
    {
        /* 临时获取锁检查服务状态 */
        pthread_mutex_lock(&g_dbus_mutex);
        service_available = is_service_available();
        pthread_mutex_unlock(&g_dbus_mutex);

        if (service_available)
        {
            printf("\n服务已可用\n");
            return TRUE;
        }

        current_time = time(NULL);
        if (current_time - start_time >= timeout_seconds)
        {
            printf("\n等待服务超时 (%d 秒)\n", timeout_seconds);
            return FALSE;
        }

        printf(".");
        fflush(stdout);
        usleep(100000); /* 等待100ms后重试，此时不持有任何锁 */
    }
}

/**
 * @brief 检查D-Bus连接状态
 */
static int check_connection_status()
{
    if (!g_connection)
    {
        fprintf(stderr, "D-Bus连接未初始化\n");
        return FALSE;
    }

    if (!dbus_connection_get_is_connected(g_connection))
    {
        fprintf(stderr, "D-Bus连接已断开\n");
        return FALSE;
    }

    return TRUE;
}

// signal_data 和 method_param 存在数据量大小限制。D-Bus 系统默认限制单个消息最大为 32MB，但为了系统稳定性和性能考虑，建议在应用层面设置更小的限制（如 1MB）